
/*****************************************************************//**
 * \file   rt_os_main.h
 * \brief  这个头文件提供一个用户的主函数接口
 * 
 * \author admin
 * \date   August 2022
 *********************************************************************/


#ifndef PPP_H_
#define PPP_H_





#include"stl_type.h"


 /// <summary>
 /// 双向链表结点。参考linux内核的链表，只包含指针域，不包含数据域。
 /// </summary>
#define ppp_buf_capacity  256
typedef void (*ppp_process)(char*, int);
typedef struct _PPP__
{
	char receive_buf[ppp_buf_capacity];
	int receive_length;
	ppp_process process;
	bool is_EscapeCharacter; //是否转义字符
}PPP;


/*
发送指令流程：
1、先计算字符串数据的CRC16校验码，并添加到字符串末尾。
2、进行字节填充（校验码可能出现0x7E的字节）。（定义转义字符为0x7D）
	1）信息字段中出现0x7E，则转换成0x7D，0x5E。
	2）信息字段中出现0x7D，则转换成0x7D，0x5D。
	3）信息字段中出现控制字符（数值小于0x20），则在该字符前加入一个0x7D字节，同时将该字符加0x20.
		比如：0x03 转换成0x7D,0x23.（大于0x20的ASCII都是可显示的字符。
		其中，值大于128的字符是扩展ASCII字符，包括特殊符号字符、外来语字母和图形符号）
3、给数据加上帧头帧尾0x7E，发送数据。
所以，只要出现0x7E，就是帧的分隔符。
*/
/// <summary>
/// 生成PPP协议的字符串.
/// </summary>
/// <param name="indata">原始数据</param>
/// <param name="indata_len">原始数据长度</param>
/// <param name="str">转化后的字符串</param>
/// <param name="str_len">转化后的字符串最大长度（缓存数组大小）</param>
/// <returns>转化后的字符串的实际长度。需要确保实际长度小于 （缓存数组最大长度-3）。</returns>
int PPP_create_string(unt8* indata, int indata_len, unt8* str, int str_len);


/*
解析指令流程：
1、先去掉帧头帧尾，逆字符填充，得到干净的数据。
2、进行CRC校验。如果校验通过，则直接调用处理函数。否则舍弃。
*/

/// <summary>
/// 解析PPP协议
/// </summary>
/// <param name="ppp">PPP的结构体</param>
/// <param name="data">接收的一字节数据</param>
void PPP_receive_data(PPP* ppp, unt8 data);


/// <summary>
/// 计算CRC校验码。
/// 发送端校验方法：设发送端发送n个字符，先计算2字节CRC校验码放到数据后面。(CRC%256)在n+1，(CRC/256)在n+2。
/// 接收端校验方法：接收端计算n+2个字符的校验码，如果校验码为0，说明校验通过，否则不通过。
/// </summary>
/// <param name="p">数据指针</param>
/// <param name="n">数据长度</param>
/// <returns>校验码</returns>
unt16 MODBUS_CRC16(unt8* p, int n);

//
void test_PPP(void);



#endif


